/*
 * Copyright (c) 2009, Artur Emagulov
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the author nor the names of any co-contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * May 28, 2009
 * platform.h
 */

#include <kiddie/autoconf.h>
#include <arm/mach/platform.h>

#ifndef _ARM_PLATFORM_H_
#define _ARM_PLATFORM_H_

#ifndef ARM
#define ARM
#endif

#ifdef __cplusplus
extern "C" {
#endif

/*
 * PSR bits
 */
#define PSR_NEGA		0x80000000	/* bit 31	*/
#define PSR_ZERO		0x40000000	/* bit 30	*/
#define PSR_CARR		0x20000000	/* bit 29	*/
#define PSR_OVRF		0x10000000	/* bit 28	*/
#define PSR_SATR		0x08000000	/* bit 27	*/
#define PSR_JAVA		0x01000000	/* bit 24	*/
#define PSR_ENDI		0x00000200	/* bit 9	*/
#define PSR_ABT_DIS		0x00000100	/* bit 8	*/
#define PSR_IRQ_DIS		0x00000080	/* bit 7	*/
#define PSR_FIQ_DIS		0x00000040	/* bit 6	*/
#define PSR_THMB_STATE	0x00000020	/* bit 5	*/
/*
 * PSR mode bits
 */
#define PSR_USR_MODE	0x00000010
#define PSR_FIQ_MODE	0x00000011
#define PSR_IRQ_MODE	0x00000012
#define PSR_SVC_MODE	0x00000013
#define PSR_ABT_MODE	0x00000017
#define PSR_UND_MODE	0x0000001B
#define PSR_SYS_MODE	0x0000001F
/* mode bits */
#define PSR_MOD_BITS	0x0000001F

/*
 * CR1 bits (CP#15 CR1)
 */
#define CR_M		(1 << 0)	/* MMU enable						*/
#define CR_A		(1 << 1)	/* Alignment abort enable			*/
#define CR_C		(1 << 2)	/* Dcache enable					*/
#define CR_W		(1 << 3)	/* Write buffer enable				*/
#define CR_P		(1 << 4)	/* 32-bit exception handler			*/
#define CR_D		(1 << 5)	/* 32-bit data address range		*/
#define CR_L		(1 << 6)	/* Implementation defined			*/
#define CR_B		(1 << 7)	/* Big endian						*/
#define CR_S		(1 << 8)	/* System MMU protection			*/
#define CR_R		(1 << 9)	/* ROM MMU protection				*/
#define CR_F		(1 << 10)	/* Implementation defined			*/
#define CR_Z		(1 << 11)	/* Implementation defined			*/
#define CR_I		(1 << 12)	/* Icache enable					*/
#define CR_V		(1 << 13)	/* Vectors relocated to 0xffff0000	*/
#define CR_RR	(1 << 14)	/* Round Robin cache replacement	*/
#define CR_L4	(1 << 15)	/* LDR pc can set T bit				*/
#define CR_DT	(1 << 16)
#define CR_IT	(1 << 18)
#define CR_ST	(1 << 19)
#define CR_FI	(1 << 21)	/* Fast interrupt(lower latency)	*/
#define CR_U		(1 << 22)	/* Unaligned access operation		*/
#define CR_XP	(1 << 23)	/* Extended page tables				*/
#define CR_VE	(1 << 24)	/* Vectored interrupts				*/

/*
 * |      |
 * +------+
 * |//////|
 * +------+ Peripherals
 * |      |
 * |      |
 * |      |
 * |      |
 * |      |
 * |      |
 * +------+
 * |//////|
 * +------+ PGD,	KERNEL_PGD
 * |//////|
 * +------+ Shared,
 * |//////|
 * +------+ Kernel,	PHYS_OFFSET
 */

#ifdef __ASSEMBLY__
#define PAGE_OFFSET			0xC0000000
#define KERNEL_PGD			0xC0004000				/* Virtual MEMORY PAGE TABLE BASE */
#define KERNEL_IVEC_PTBL	0xC0001000				/* Ivector page table virtual address base */
#else
#define PAGE_OFFSET			__page_offset
#define KERNEL_PGD			__kernel_vpgd				/* Virtual MEMORY PAGE TABLE BASE */
#define KERNEL_IVEC_PTBL	__ivec_pt_base				/* Ivector page table virtual address base */
#endif

#define PHYS_OFFSET			MACH_RAM_BASE				/* PHYSICAL MEMORY BASE */
#define PHYS_RAM_SIZE		MACH_RAM_SIZE				/* Maximum size of RAM */

#define PAGE_SIZE			0x1000						/* default page size */

#define KERNEL_BASE			PAGE_OFFSET					/* VIRTUAL MEMORY KERNEL START ADDRESS */
/* #define KERNEL_OFFSET		0x8000 */				/* KERNEL ACTUAL ADDRESS */
#define KERNEL_START		__kernel_vstart				/* VIRTUAL MEMORY KERNEL START ADDRESS */
#define KERNEL_END			_end
#define KERNEL_MAX			0xffffffff					/* 4GB maximum */
#define HW_PROFILE_INFO		__boot_info_p

#define USER_BASE			0x00000000
#define USER_MAX				0x80000000
#define KERNEL_MAP_MEM_SIZE 0x00200000
#define KERNEL_DIRECTMAP_MBYTES ((KERNEL_MAP_MEM_SIZE>>20)-1)

/* #define SVC_MODE				0x00000013 */
#define PSR_F_BIT			0x00000040
#define PSR_I_BIT			0x00000080


#define BOOT_PTE0			0x00001000
#define INT_STACK			0x00001000
#define BOOT_STACK			0x00002800
/* The size of our stack (16KB). */
#define STACK_SIZE			0x4000
#define TASK_STACK_SIZE		0x400

/* Number of IRQ handlers */
#define IRQ_ENTRIES	32
#define IRQ_VECTOR_BASE		0xffff0000			/* base address of exception vector */
/*
 * 'C' handler attributes (if used)
 */
#ifndef __ASSEMBLY__

/* these are symbols from ld-script*/
extern unsigned long __page_offset;
extern unsigned long __kernel_vstart;
extern unsigned long __kernel_vpgd;
extern unsigned long __ivec_pt_base;
extern unsigned long __boot_info_p;
extern unsigned long _end;
/* init section symbols */
extern unsigned long __initcall_start;
extern unsigned long __early_initcall_end;
extern unsigned long __initcall_end;
extern unsigned long exception_vector_start;
extern unsigned long exception_vector_end;

/*---------------------------------*/

#define __irq __attribute__((interrupt("IRQ"))
#define __fiq __attribute__((interrupt("FIQ"))
#define __swi __attribute__((interrupt("SWI"))
#define __abt __attribute__((interrupt("ABORT"))
#define __und __attribute__((interrupt("UNDEF"))

/* TODO !!!!!!!!!!!!!! */
#ifndef CONFIG_MMU
#define CONFIG_MMU
#endif

#ifdef CONFIG_MMU

	#define PAGE_OFFSET_ADR	&PAGE_OFFSET
	#define __pa(x)	(void *)((unsigned long)(x) - (unsigned long)PAGE_OFFSET_ADR + (unsigned long)PHYS_OFFSET)
	#define __va(x)	(void *)((unsigned long)(x) + (unsigned long)PAGE_OFFSET_ADR - (unsigned long)PHYS_OFFSET)
	#define phys_to_virt(pa)	(void *)((unsigned long)(pa) + (unsigned long)PAGE_OFFSET_ADR - (unsigned long)PHYS_OFFSET)
	#define virt_to_phys(va)	(void *)((unsigned long)(va) - (unsigned long)PAGE_OFFSET_ADR + (unsigned long)PHYS_OFFSET)
	#define bus_to_virt(pa) (void *)((unsigned long)pa + (unsigned long)V_IO_BASE - (unsigned long)P_IO_BASE)
	#define virt_to_bus(va) (void *)((unsigned long)va - (unsigned long)V_IO_BASE + (unsigned long)P_IO_BASE)

#else

	#define PAGE_OFFSET_ADR	0
	#define __pa(x)	x
	#define __va(x)	x
	#define phys_to_virt(pa)		pa
	#define virt_to_phys(va)		va
	#define bus_to_virt(pa)		pa
	#define virt_to_bus(va)		va

#endif

/**
 * Page directory entry
 */
#define PDE_PRESENT	0x00000001
#define PDE_WRITE	0x00000002
#define PDE_USER	0x00000004
#define PDE_WTHRU	0x00000008
#define PDE_NCACHE	0x00000010
#define PDE_ACCESS	0x00000020
#define PDE_SIZE	0x00000080
#define PDE_AVAIL	0x00000e00
#define PDE_ADDRESS	0xfffff000

/**
 * Page table entry
 */
#define PTE_PRESENT	0x00000001
#define PTE_WRITE	0x00000002
#define PTE_USER	0x00000004
#define PTE_WTHRU	0x00000008
#define PTE_NCACHE	0x00000010
#define PTE_ACCESS	0x00000020
#define PTE_DIRTY	0x00000040
#define PTE_AVAIL	0x00000e00
#define PTE_ADDRESS	0xfffff000

/**
 *  Virtual and physical address translation
 */
#define pgd_len()		(PAGE_SIZE / sizeof(pde_t))
#define pgt_len()		(PAGE_SIZE / sizeof(pte_t))
#define pgd_idx(virt)    (int)((((vaddr_t)(virt)) >> 22) & 0x3ff)
#define pgt_idx(virt)    (int)((((vaddr_t)(virt)) >> 12) & 0x3ff)

#define pgt_present(vpgd, virt)  (vpgd[pgd_idx(virt)] & PDE_PRESENT)

#define page_present(vpgt, virt) (vpgt[pgt_idx(virt)] & PTE_PRESENT)

#define vpgd_virt_to_vpgt(vpgd, virt) \
            (page_table_t)phys_to_virt(vpgd[pgd_idx(virt)] & PDE_ADDRESS)

#define vpgt_virt_to_page(vpte, virt) \
            (vpte[pgt_idx(virt)] & PTE_ADDRESS)

#endif /* __ASSEMBLY__ */

#ifdef __cplusplus
}
#endif

#endif /* _ARM_PLATFORM_H_ */
